
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include "../aprtools/APRFile.h"
#include "../iface/SQLiteInterface.h"
#include "../utils/StringUtils.h"
#include "SQLiteDB.h"

#include "acquire_config.h"

// Need to enforce sanitisation at this level or bad things may
// happen!

/** This opens or creates a database. The filename should not have any
 * extension. If the .db is not found, the .sql will be used to
 * populate the database. If the .sql also does not exist, a new
 * database will be created.
 * 
 * @param filename The name of the files containing the database. As
 * this refers to both .sql and .db files, this should not have a file
 * type extension.
 * 
 * @param persist A boolean flag that sets whether to save the
 * database to disk. */
SQLiteDB::SQLiteDB(const char *filename, int persist)
{
   dbmutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
   autolock = new SQLiteAutoLock(dbmutex);
   if (filename)
   {
      dumpfilename = StringUtils::varprintf("%s.sql", filename);
      char *dfile2 = dumpfilename;
      dumpfilename = APRFile::expandPathToNewString(dfile2);
      free(dfile2);
   } else
   {
      dumpfilename = NULL;
   }
   db = NULL;
   int res;
   int dbexists = 0;
   if ((persist) && (filename))
   {
      char *realfname = StringUtils::varprintf("%s.db", filename);
      char *ffile2 = realfname;
      realfname = APRFile::expandPathToNewString(ffile2);
      free(ffile2);
      FILE *FP = fopen(realfname, "r");
      if (FP != NULL)
      {
         fclose(FP);
         dbexists = 1;
      } else errprint("Cannot find database '%s'", realfname);
      res = sqlite3_open(realfname, &db);
      free(realfname);
   } else
   {
      res = sqlite3_open(":memory:", &db);
   }
   if (res)
   {
      CheckSQLiteError("Cannot open database - ", db);
      sqlite3_close(db);
      db = NULL;
      return;
   }
   if (!db) return;
   int mret = 0;
   if ((dumpfilename) && (!dbexists))
      mret = loadSQL(dumpfilename);
   if (mret)
      errprint("SQL read unsuccessful, creating new database '%s'", filename);
   if (!(persist))
   {
      free(dumpfilename);
      dumpfilename = NULL;
   }
}

/** This destructor dumps the database to SQL and close the
 * database. */
SQLiteDB::~SQLiteDB()
{
   if (db)
   {
      if (dumpfilename)
      {
         dumpDatabaseToSQL(dumpfilename);
         free(dumpfilename);
      }
      sqlite3_close(db);
   }
   delete autolock;
   autolock = NULL;
   sqlite3_mutex_free(dbmutex);
}

/** Instantly execute the given SQL query on the database.
 * 
 * @param query The SQL query string.
 * 
 * @return Returns zero on success, non-zero on failure. */
int SQLiteDB::sqlInstantExec(const char *query)
{
   sqlite3_stmt *sql;
   const char *unused;
   if (!db)
   {
      errprint("Database not open");
      return -1;
   }
   SQLiteAutoLock thislock(getAutoLock());
   if (sqlite3_prepare_v2(db, query, strlen(query)+1, &sql, &unused))
   {
      errprint("sql prepare for %s: %s", query, sqlite3_errmsg(db));
      return -1;
   }
   if (sqlite3_step(sql) != SQLITE_DONE)
   {
      errprint("sql step for %s: %s", query, sqlite3_errmsg(db));
      sqlite3_finalize(sql);
      return -1;
   }
   if (sqlite3_finalize(sql))
   {
      errprint("sql finalize for %s: %s", query, sqlite3_errmsg(db));
      return -1;
   }
   return 0;
}

/** Instantly execute the given variadically formatted SQL query on
 * the database.
 * 
 * @param query The printf-style format string representing the SQL
 * query.
 * 
 * @return Returns zero on success, non-zero on failure. */
int SQLiteDB::sqlInstantExecf(const char *query, ...)
{
   // Deperately needs StringSanitiser but probably will require
   // building a wrapper around varargs!
   va_list args;
   va_start(args, query);
   char *actual = StringUtils::varprintf_va(query, args);
   va_end(args);
   int result = sqlInstantExec(actual);
   free(actual);
   return result;
}

/** Compile and prepare the given SQL query string for execution. This
 * function is private and not locked (it is assumed that locking is
 * handled by the caller).
 * 
 * @param query The SQL query string.
 * 
 * @return Returns the SQL statement object to be used further in the
 * execution process. */
sqlite3_stmt *SQLiteDB::sqlCompile(const char *query)
{
   sqlite3_stmt *sql;
   const char *unused;
   if (!db)
   {
      errprint("Database not open");
      return NULL;
   }
   if (sqlite3_prepare_v2(db, query, strlen(query)+1, &sql, &unused))
   {
      errprint("sql prepare for %s: %s", query, sqlite3_errmsg(db));
      return NULL;
   }
   return sql;
}

/** Scan a row resulting from the execution of an SQL statement into a
 * bespoke format string similarly to scanf.
 * 
 * @param sql SQL statement to be executed.
 * 
 * @param rowformat Bespoke formatting string to identify the variadic
 * set of destination pointers.
 * 
 * @return Returns 1 if the query completes, 0 if it is incomplete and
 * less than zero on an error. */
int SQLiteDB::sqlScanRowStatement(sqlite3_stmt *sql, const char *rowformat, ...)
{
   int column = 0;
   va_list ap;
   
   int *i;
   const char **c;
   double *d;
   
   int result = -1;
   
   if (!db)
   {
      errprint("Database not open");
      return -1;
   }
   SQLiteAutoLock thislock(getAutoLock());
   switch (sqlite3_step(sql))
   {
      case SQLITE_ROW:
         if (rowformat == NULL) return 0;
         va_start(ap, rowformat);
         while (rowformat[column] != '\0')
         {
            switch (rowformat[column])
            {
               case 'd':
                  i = va_arg(ap, int *);
                  *i = sqlite3_column_int(sql, column++);
                  break;
               case 's':
                  c = va_arg(ap, const char **);
                  *c = (const char *)sqlite3_column_text(sql, column++);
                  break;
               case 'f':
                  d = va_arg(ap, double *);
                  *d = sqlite3_column_double(sql, column++);
                  break;
               case '*':
                  column++;
                  break;
               default:
                  errprint("unknown format '%c'", rowformat[column]);
                  va_end(ap);
                  return -1;
            }
         }
         va_end(ap);
         return 0;
         break;
      case SQLITE_DONE:
         return 1;
         break;
      default:
         errprint("sql step: %s", sqlite3_errmsg(db));
         return -1;
         break;
   }
}

/** Scans a database row resulting from the execution of the given
 * variadically formatted SQL query on the database.
 * 
 * @param csql The printf-style format string representing the SQL
 * query.
 * 
 * @return A vector of strings of each of the arguments in turn, the
 * caller takes on the responsibility of freeing both the string list
 * and the individual strings. This can be achieved most effectively
 * with a call to the StringUtils::destroyStringList method. */
std::vector<char *> *SQLiteDB::sqlScanRowTextf(const char *csql, ...)
{
   // Deperately needs StringSanitiser but probably will require
   // building a wrapper around varargs!
   va_list args;
   va_start(args, csql);
   char *actual = StringUtils::varprintf_va(csql, args);
   va_end(args);
   std::vector<char *> *result = sqlScanRowText(actual);
   free(actual);
   return result;
}

/** Returns a database row resulting from the execution of the given
 * SQL query on the database.
 * 
 * @param csql The SQL query string.
 * 
 * @return A vector of strings of each of the arguments in turn, the
 * caller takes on the responsibility of freeing both the string list
 * and the individual strings. This can be achieved most effectively
 * with a call to the StringUtils::destroyStringList method. */
std::vector<char *> *SQLiteDB::sqlScanRowText(const char *csql)
{
   SQLiteAutoLock thislock(getAutoLock());
   sqlite3_stmt *squery = sqlCompile(csql);
   std::vector<char *> *info = sqlScanRowStatement(squery);
   sqlFinalize(squery);
   return info;
}

/** Returns a database row resulting from the execution of the given
 * prepared SQL statement on the database.
 * 
 * @param sql SQL statement to run.
 * 
 * @return A vector of strings of each of the arguments in turn, the
 * caller takes on the responsibility of freeing both the string list
 * and the individual strings. This can be achieved most effectively
 * with a call to the StringUtils::destroyStringList method. */
std::vector<char *> *SQLiteDB::sqlScanRowStatement(sqlite3_stmt *sql)
{
   const char *c;
   char *ctemp;

   if (!db)
   {
      errprint("database not open");
      return NULL;
   }
   SQLiteAutoLock thislock(getAutoLock());
   std::vector<char *> *strarray = new std::vector<char *>();
   int sql_res = sqlite3_step(sql);
   int columns = sqlite3_column_count(sql);
   switch (sql_res)
   {
      case SQLITE_ROW:
         for (int i = 0; i < columns; i++)
         {
            c = (const char *)sqlite3_column_text(sql, i);
            ctemp = (char *)malloc(sizeof(char)*(strlen(c)+1));
            strcpy(ctemp, c);
            strarray->push_back(ctemp);
         }
         break;
      case SQLITE_DONE:
         // No strings, so can delete immediately
         if (strarray->size() > 0) errprint("warning non-empty string list leaking");
         delete strarray;
         strarray = NULL;
         break;
      default:
         errprint("sql step: %s", sqlite3_errmsg(db));
         if (strarray->size() > 0) errprint("warning non-empty string list leaking");
         delete strarray;
         strarray = NULL;
         break;
   }
   return strarray;
}

/** Scans a database table (a number of rows) resulting from the
 * execution of the given variadically formatted SQL query on the
 * database.
 * 
 * @param csql The printf-style format string representing the SQL
 * query.
 * 
 * @return A vector of strings of each of the arguments in turn, the
 * caller takes on the responsibility of freeing both the string list
 * and the individual strings. This can be achieved most effectively
 * with a call to the StringUtils::destroyStringList method. */
std::vector<char *> *SQLiteDB::sqlScanAllTextf(const char *csql, ...)
{
   va_list args;
   va_start(args, csql);
   char *actual = StringUtils::varprintf_va(csql, args);
   va_end(args);
   std::vector<char *> *result = sqlScanAllText(actual);
   free(actual);
   return result;
}

/** Scans a database table (a number of rows) resulting from the
 * execution of the given SQL query string on the database.
 * 
 * @param csql The string representing the SQL query.
 * 
 * @return A vector of strings of each of the arguments in turn, the
 * caller takes on the responsibility of freeing both the string list
 * and the individual strings. This can be achieved most effectively
 * with a call to the StringUtils::destroyStringList method. */
std::vector<char *> *SQLiteDB::sqlScanAllText(const char *csql)
{
   SQLiteAutoLock thislock(getAutoLock());
   sqlite3_stmt *squery = sqlCompile(csql);
   std::vector<char *> *info = sqlScanAllStatement(squery);
   sqlFinalize(squery);
   return info;
}

/** Scans a database table (a number of rows) resulting from the
 * execution of the given prepared SQL statement on the database.
 * 
 * @param sql SQL statement to run.
 * 
 * @return A vector of strings of each of the arguments in turn, the
 * caller takes on the responsibility of freeing both the string list
 * and the individual strings. This can be achieved most effectively
 * with a call to the StringUtils::destroyStringList method. */
std::vector<char *> *SQLiteDB::sqlScanAllStatement(sqlite3_stmt *sql)
{
   const char *c;
   char *ctemp;

   if (!db)
   {
      errprint("Database not open");
      return NULL;
   }
   SQLiteAutoLock thislock(getAutoLock());
   std::vector<char *> *strarray = new std::vector<char *>();
   int sql_res;
   while ((sql_res = sqlite3_step(sql)) == SQLITE_ROW)
   {
      int columns = sqlite3_column_count(sql);
      for (int i = 0; i < columns; i++)
      {
         c = (const char *)sqlite3_column_text(sql, i);
         ctemp = (char *)malloc(sizeof(char)*(strlen(c)+1));
         strcpy(ctemp, c);
         strarray->push_back(ctemp);
      }
   }
   switch (sql_res)
   {
      case SQLITE_DONE:
         break;
      default:
         errprint("sql step: %s", sqlite3_errmsg(db));
         if (strarray->size() > 0) errprint("warning non-empty string list leaking");
         delete strarray;
         strarray = NULL;
         break;
   }
   return strarray;
}

/** Finalize the SQL execution process. This frees any bits and pieces
 * that were holding results from the execution. This is assumed to be
 * called from inside any database locks.
 * 
 * @param sql SQL statement to finalise.
 * 
 * @return Zero on success, non-zero on failure. */
int SQLiteDB::sqlFinalize(sqlite3_stmt *sql)
{
   if (sqlite3_finalize(sql))
   {
      errprint("sql finalize: %s", sqlite3_errmsg(db));
      return -1;
   }
   return 0;
}

/** Backup the constituent SQL commands of the database to the
 * specified text file. */
void SQLiteDB::backup()
{
   dumpDatabaseToSQL(dumpfilename);
}

/** Backup the constituent SQL commands of the database to the
 * specified text file.
 * 
 * @param filename Filename to write the SQL to.
 * 
 * @return Returns zero on success, non-zero on failure. */
int SQLiteDB::dumpDatabaseToSQL(const char *filename)
{
//   char *errmsg = NULL;
   FILE *FP;
   FP = fopen(filename, "w");
   const char *tablename;
   const char *tablecsql;
   std::vector<char *> *alltablesnames = new std::vector<char *>();
   // Extract table names and the sql needed to create them
   SQLiteAutoLock thislock(getAutoLock());
   sqlite3_stmt *sqlstat = sqlCompile("select tbl_name,sql from sqlite_master where type='table';");
   while (sqlScanRowStatement(sqlstat, "ss", &tablename, &tablecsql) == 0)
   {
      // Build a list of the tables
      char *ttablename = (char *)malloc(sizeof(char)*(strlen(tablename)+1));
      strcpy(ttablename, tablename);
      alltablesnames->push_back(ttablename);
      // Print the sql statements to create each table to the file
      fprintf(FP, "%s;\n", tablecsql);
   }
   sqlFinalize(sqlstat);
   // Now dump tables
   for (uint32_t i = 0; i < alltablesnames->size(); i++)
   {
      dumpTableToSQL(FP, alltablesnames->at(i));
      free(alltablesnames->at(i));
   }
   delete alltablesnames;
   fclose(FP);
   return 0;
}

/** Dump the specified table out to the given file stream.
 * 
 * @param FP File pointer to dump the table SQL into.
 * 
 * @param tablename The name of the table in the database to dump.
 * 
 * @return Returns zero on success, non-zero on failure. */
int SQLiteDB::dumpTableToSQL(FILE *FP, const char *tablename)
{
   const char *sqlgettable = "select * from '%s';";
   char *sqlgettablefull = (char *)malloc(sizeof(char)*(strlen(sqlgettable)+strlen(tablename)+1));
   sprintf(sqlgettablefull, sqlgettable, tablename);
   SQLiteAutoLock thislock(getAutoLock());
   sqlite3_stmt *sqlstat = sqlCompile(sqlgettablefull);
   std::vector<char *> *strlist = NULL;
   while ((strlist = sqlScanRowStatement(sqlstat)) != NULL)
   {
      fprintf(FP, "insert into \"%s\" values(", tablename);
      for (uint32_t i = 0; i < strlist->size(); i++)
      {
         fprintf(FP, "'%s'%s", strlist->at(i), ((i < (strlist->size() - 1)) ? ", " : ");\n"));
      }
      // Properly destroy
      StringUtils::destroyStringList(strlist);
      strlist = NULL;
   }
   sqlFinalize(sqlstat);
   free(sqlgettablefull);
   return 0;
}

/** Checks to determine whether the given character is whitespace.
 * 
 * @param wht Character to check.
 * 
 * @return Returns 1 if it is whitespace, 0 for other printable
 * characters. */
int SQLiteDB::isWhitespace(char wht)
{
   switch (wht)
   {
      case ' ':
      case '\t':
      case '\r':
      case '\n':
         return 1;
      default:
         return 0;
   }
}

/** Run a file of SQL queries on the database.
 * 
 * @param filename The filename of the file of SQL queries.
 * 
 * @return Returns zero for success, 1 for failed to read file and
 * less than zero for other errors. */
int SQLiteDB::loadSQL(const char *filename)
{
   if (!db)
   {
      errprint("Database not open");
      return -1;
   }
   FILE *FP;
   FP = fopen(filename, "r");
   if (!FP)
   {
      errprint("Could not open sql file");
      return 1;
   }
   std::vector<char> *scratch = new std::vector<char>();
   while (!(feof(FP)))
   {
      int chr = ' ';
      while ((isWhitespace(chr = fgetc(FP))) && (!(feof(FP))));
      scratch->push_back(chr);
      if (chr == -1) break;
      while (((chr = fgetc(FP)) != ';') && (!(feof(FP))))
         scratch->push_back(chr);
      if (chr == -1) break;
      if (chr == ';') scratch->push_back(chr);
      if (scratch->size() > 0)
      {
         scratch->push_back('\0');
         int res = sqlInstantExec(&(scratch->at(0)));
         if (res != 0) return res;
         scratch->clear();
      }
   }
   fclose(FP);
   delete scratch;
   return 0;
}

/** Sanitises a string in-place.
 * 
 * @param sanstr String to be modified in-place into nice SQL friendly
 * plain text. */
void SQLiteDB::stringSanitiser(char *sanstr)
{
   // Well, more to remove illegal characters than anything else
   int tstrlen = strlen(sanstr);
   for (int i = 0; i < tstrlen; i++)
   {
      int rep = (sanstr[i] == ';') || (sanstr[i] == '*') || (sanstr[i] == '\'');
      sanstr[i] = (rep) ? '_' : sanstr[i];
   }
}

/** Checks to see if the given tables exist and create them if they do
 * not.
 * 
 * Tables are given in alternating table name and table definition
 * format. For instance:
 * 
 * SQLiteDB::ensureTablesAreCreated(2, "table1", "(key char(1))",
 * "table2", "(key char(2))");
 * 
 * would be acceptable.
 * 
 * @param notables Number of tables to be created. */
void SQLiteDB::ensureTablesAreCreated(int notables, ...)
{
   std::vector<char *> *cstrlist = sqlScanAllText("select tbl_name from sqlite_master where type='table';");
   int *table_exist_vector = (int *)malloc(sizeof(int)*notables);
   memset(table_exist_vector, 0, sizeof(int)*notables);
   va_list args;
   va_start(args, notables);
   if (cstrlist)
   {
      for (int j = 0; j < notables; j++)
      {
         char *this_tablename = va_arg(args, char *);
         for (int i = 0; i < (int)(cstrlist->size()); i++)
         {
            char *thisname = cstrlist->at(i);
            table_exist_vector[j] |= (strcmp(this_tablename, thisname) == 0);
         }
         char *this_tabledef = va_arg(args, char *);
         if (!(table_exist_vector[j]))
         {
            char *actual = StringUtils::varprintf("create table '%s' %s;", this_tablename, this_tabledef);
            sqlInstantExec(actual);
            free(actual);
         }
      }
   }
   va_end(args);
   free(table_exist_vector);
   StringUtils::destroyStringList(cstrlist);
}

/** Get a primitive int integer as the result of the execution of a
 * prepared SQL statement.
 * 
 * @param[out] result A pointer to a place to put this integer.
 * 
 * @param sql The prepared SQL statement to execute.
 * 
 * @return Zero on success, non-zero on failure. */
int SQLiteDB::sqlGetSingleIntStatement(int *result, sqlite3_stmt *sql)
{
   if (!db) { errprint("database not open"); return 0; }
   if (!result) { errprint("NULL result pointer"); return 0; }
   SQLiteAutoLock thislock(getAutoLock());
   int sql_res = sqlite3_step(sql);
   int columns = sqlite3_column_count(sql);
   *result = sqlite3_column_int(sql, 0);
   while (sql_res == SQLITE_ROW)
   {
      sql_res = sqlite3_step(sql);
      int stat_res = sqlite3_column_int(sql, 0);
      if (stat_res)
         errprint("trailing result row '%d'", stat_res);
   }
   if (columns > 1)
      errprint("ignored trailing columns");
   return 1;
}

/** Get a primitive double real number as the result of the execution
 * of a prepared SQL statement.
 * 
 * @param[out] result A pointer to a place to put this real number.
 * 
 * @param sql The prepared SQL statement to execute.
 * 
 * @return Zero on success, non-zero on failure. */
int SQLiteDB::sqlGetSingleDoubleStatement(double *result, sqlite3_stmt *sql)
{
   if (!db) { errprint("database not open"); return 0; }
   if (!result) { errprint("NULL result pointer"); return 0; }
   SQLiteAutoLock thislock(getAutoLock());
   int sql_res = sqlite3_step(sql);
   int columns = sqlite3_column_count(sql);
   *result = sqlite3_column_double(sql, 0);
   if (sql_res == SQLITE_ROW)
      errprint("ignoring trailing rows");
   if (columns > 1)
      errprint("ignored trailing columns");
   return 1;
}

/** Get a string as the result of the execution of a prepared SQL
 * statement.
 * 
 * @param[out] result A pointer to a place to put the string
 * pointer. The caller has the responsibility for freeing the string.
 * 
 * @param sql The prepared SQL statement to execute.
 * 
 * @return Zero on success, non-zero on failure. */
int SQLiteDB::sqlGetSingleStringStatement(char **result, sqlite3_stmt *sql)
{
   if (!db) { errprint("database not open"); return 0; }
   if (!result) { errprint("NULL result pointer"); return 0; }
   SQLiteAutoLock thislock(getAutoLock());
   int sql_res = sqlite3_step(sql);
   int columns = sqlite3_column_count(sql);
   const char *stat_res = (const char *)sqlite3_column_text(sql, 0);
   if (stat_res)
   {
      *result = (char *)malloc(sizeof(char)*(strlen(stat_res)+1));
      strcpy(*result, stat_res);
   }
   while (sql_res == SQLITE_ROW)
   {
      sql_res = sqlite3_step(sql);
      stat_res = (const char *)sqlite3_column_text(sql, 0);
      if (stat_res)
         errprint("trailing result row '%s'", stat_res);
   }
   if (columns > 1)
      errprint("ignored trailing columns");
   return 1;
}

/** Get a primitive int integer as the result of the execution of a
 * variadically formatted SQL query string.
 * 
 * @param[out] result A pointer to a place to put this integer.
 * 
 * @param csql The printf-style formatting string for the SQL query.
 * 
 * @return Zero on success, non-zero on failure. */
int SQLiteDB::sqlGetSingleIntf(int *result, const char *csql, ...)
{
   // Deperately needs StringSanitiser but probably will require
   // building a wrapper around varargs!
   va_list args;
   va_start(args, csql);
   char *actual = StringUtils::varprintf_va(csql, args);
   va_end(args);
   SQLiteAutoLock thislock(getAutoLock());
   sqlite3_stmt *squery = sqlCompile(actual);
   int res = sqlGetSingleIntStatement(result, squery);
   sqlFinalize(squery);
   free(actual);
   return res;
}

/** Get a primitive double real as the result of the execution of a
 * variadically formatted SQL query string.
 * 
 * @param[out] result A pointer to a place to put this double real.
 * 
 * @param csql The printf-style formatting string for the SQL query.
 * 
 * @return Zero on success, non-zero on failure. */
int SQLiteDB::sqlGetSingleDoublef(double *result, const char *csql, ...)
{
   // Deperately needs StringSanitiser but probably will require
   // building a wrapper around varargs!
   va_list args;
   va_start(args, csql);
   char *actual = StringUtils::varprintf_va(csql, args);
   va_end(args);
   SQLiteAutoLock thislock(getAutoLock());
   sqlite3_stmt *squery = sqlCompile(actual);
   int res = sqlGetSingleDoubleStatement(result, squery);
   sqlFinalize(squery);
   free(actual);
   return res;
}

/** Get a string as the result of the execution of a variadically
 * formatted SQL query string.
 * 
 * @param[out] result A pointer to a place to put the string
 * pointer. The caller has the responsibility for freeing the string.
 * 
 * @param csql The printf-style formatting string for the SQL query.
 * 
 * @return Zero on success, non-zero on failure. */
int SQLiteDB::sqlGetSingleStringf(char **result, const char *csql, ...)
{
   // Deperately needs StringSanitiser but probably will require
   // building a wrapper around varargs!
   va_list args;
   va_start(args, csql);
   char *actual = StringUtils::varprintf_va(csql, args);
   va_end(args);
   SQLiteAutoLock thislock(getAutoLock());
   sqlite3_stmt *squery = sqlCompile(actual);
   int res = sqlGetSingleStringStatement(result, squery);
   sqlFinalize(squery);
   free(actual);
   return res;
}

/** Tests whether the table exists.
 * 
 * @param tablename Table name format string to check for existence.
 * 
 * @return Count of table with that name, so one for table does exist,
 * zero if the table does not exist. */
int SQLiteDB::sqlCheckTableExists(const char *tablename, ...)
{
   va_list args;
   va_start(args, tablename);
   char *actual = StringUtils::varprintf_va(tablename, args);
   va_end(args);
   int tableno = 0;
   sqlGetSingleIntf(&tableno, "select count(tbl_name) from sqlite_master where type='table' and tbl_name='%s';", actual);
   free(actual);
   return tableno;
}
